import { Config } from "@/entities/Config";
import { initORM } from "@/utils";
import { NextApiRequest, NextApiResponse } from "next";
import { getCurrentUser } from "./user";
import { getApp, getUserListOfApp } from "./app";
import { User } from "@/entities/User";
import { App } from "@/entities/App";
import { pickData, sleep } from "@/utils/base";

export async function getConfigs(req: NextApiRequest) {
  const checkAuthResult = await checkViewConfigAuth(req);
  if (!checkAuthResult.success) {
    return checkAuthResult;
  }

  const em = await initORM();
  const query = req.query ?? {};
  const conditions = {
    ...(query.appid ? { app: { id: Number(query.appid) } } : {}),
    ...(query.env === "any" ? {} : { env: query.env }),
    ...(query.name ? { name: { $like: `%${query.name}%` } } : {}),
    ...(query.disabled ? { disabled: Number(query.disabled) } : {}),
  };
  // console.log("🚀 ~ getConfigs ~ conditions:", conditions);
  const configs = await em.find(Config, conditions, {
    populate: ["creator", "editor", "app"],
  });

  return {
    success: true as const,
    message: "Query Configs success",
    data: { configs },
  };
}

export async function checkViewConfigAuth(req: NextApiRequest) {
  const appSecret = req.headers["x-app-secret"];
  const appId = Number(req.query.appid);

  if (appSecret) {
    const em = await initORM();
    const app = await em.findOne(App, { id: appId, secret: appSecret });
    if (!app) {
      return {
        success: false as const,
        data: {},
        message: "App secret is invalid",
      };
    } else {
      return {
        success: true as const,
        data: {},
        message: "Check App secret success",
      };
    }
  }

  const curUser = await getCurrentUser(req);

  if (!curUser) {
    return {
      success: false as const,
      data: {},
      message: "User not found",
    };
  }

  const isSuperUser = curUser.id === 1;

  // only super user or this app users can change status
  const appUsersResult = await getUserListOfApp(req);
  if (!appUsersResult.success || !appUsersResult.data.users) {
    return {
      success: false as const,
      data: {},
      message: "You are not user of this app",
    };
  }

  const users = appUsersResult.data.users as unknown as User[];
  const isAppUser = users.some((user) => user.id === curUser.id);

  if (!isSuperUser && !isAppUser) {
    return {
      success: false as const,
      data: {},
      message: "You are not super user or an user of this app",
    };
  }

  return {
    success: true as const,
    data: {},
    message: "Check view config auth success",
  };
}

export async function getConfig(req: NextApiRequest) {
  const configid = req.query.configid || req.body?.configid;
  //   const curUser = await getCurrentUser(req);

  const checkAuthResult = await checkViewConfigAuth(req);
  if (!checkAuthResult.success) {
    return checkAuthResult;
  }

  const em = await initORM();
  const config = await em.findOne(Config, Number(configid));

  if (!config) {
    return {
      success: false,
      data: {},
      message: "Config not found",
    };
  }

  return {
    success: true,
    data: config,
    message: "Query config success",
  };
}

export async function updateConfig(
  req: NextApiRequest,
  res: NextApiResponse<APIRes>
) {
  const { configid, name, disabled, introduce, type } = req.body ?? {};

  const configResult = await getConfig(req);

  if (!configResult.success) {
    res.status(400).json(configResult as APIRes);
    return;
  }

  const config = configResult.data as Config;

  const keys = [
    "name",
    "disabled",
    "introduce",
    "type",
    "value",
    "env",
  ] as const;

  keys.forEach((key) => {
    if (req.body[key] !== undefined) {
      Object.assign(config, { [key]: req.body[key] as string });
    }
  });

  const em = await initORM();

  const curUser = await getCurrentUser(req);
  if (!curUser) {
    res.status(400).json({
      success: false,
      data: {},
      message: "User not found",
    });
  } else {
    const userRef = em.getReference(User, curUser.id, { wrapped: true });
    config.editor = userRef;
  }

  await em.persistAndFlush(config);

  res.status(200).json({
    success: true,
    data: config,
    message: "Update config success",
  });
}

export async function createConfig(
  req: NextApiRequest,
  res: NextApiResponse<APIRes>
) {
  const checkauthResult = await checkViewConfigAuth(req);
  if (!checkauthResult.success) {
    return res.status(400).json(checkauthResult);
  }

  const em = await initORM();
  const curUser = await getCurrentUser(req);
  if (!curUser) {
    res.status(400).json({
      success: false,
      data: {},
      message: "User not found",
    });
    return;
  }

  const curAppResult = await getApp(req);
  if (!curAppResult.success) {
    res.status(400).json(curAppResult as APIRes);
    return;
  }

  const curApp = curAppResult.data as App;

  const data = Object.assign({}, req.body ?? {});
  if (Array.isArray(data.value)) {
    data.value = JSON.stringify(data.value);
  }
  const config = await em.create(
    Config,
    Object.assign({ creator: curUser, editor: curUser, app: curApp }, data)
  );
  await em.persistAndFlush(config);
  await sleep(1);

  res.status(200).json({
    success: true,
    data: pickData(config, ["id", "name"]),
    message: "Config created",
  });
}

export async function delConfig(req: NextApiRequest) {
  const configid = req.query.configid || req.body?.configid;
  //   const curUser = await getCurrentUser(req);

  const em = await initORM();
  const config = await em.findOne(Config, Number(configid));

  if (!config) {
    return {
      success: false,
      data: {},
      message: "Config not found",
    };
  }

  await em.removeAndFlush(config);

  return {
    success: true,
    data: { id: config.id },
    message: "Remove config success",
  };
}
